package com.example.springbootdemo.threadpool;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;

public class MyThreadPool {
    int coreThreadNum = 3;
    int maxThreadNum = 4;
    BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<>(10);
    int timeout = 30;
    TimeUnit time = TimeUnit.SECONDS;
    RejectHandle receiver = new ThrowRejectHandle();

    public MyThreadPool() {

    }

    public MyThreadPool(int coreThreadNum, int maxThreadNum, BlockingQueue<Runnable> blockingQueue, int timeout, TimeUnit time, RejectHandle receiver) {
        this.coreThreadNum = coreThreadNum;
        this.maxThreadNum = maxThreadNum;
        this.blockingQueue = blockingQueue;
        this.timeout = timeout;
        this.time = time;
        this.receiver = receiver;
    }



    List<Thread> coreThreads = new ArrayList<>(coreThreadNum);
    List<Thread> supportedThreads = new ArrayList<>();


    public void execute(Runnable a) {
        if (coreThreads.size() <= coreThreadNum){
            Thread thread = new Thread(new CoreRunnable(),coreThreads.size()+"");
            coreThreads.add(thread);
            thread.start();
        }

        if (blockingQueue.offer(a)){
            return;
        }
        if (coreThreads.size() + supportedThreads.size() <= maxThreadNum ){
            String name = Thread.currentThread().getName();
            Thread thread = new Thread(new SupportedRunnable(a), "supported-" + name + new Date().getTime());
            supportedThreads.add(thread);
            thread.start();
        }

        if (!blockingQueue.offer(a)){
            receiver.reject(a,this);
        }
    }
    private class CoreRunnable implements Runnable {
        @Override
        public void run() {
            while (true){
                try {
                    final Runnable take = blockingQueue.take();
                    take.run();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private class SupportedRunnable implements Runnable {

        Runnable currentRunnable;

        public SupportedRunnable(Runnable currentRunnable) {
            this.currentRunnable = currentRunnable;
        }

        @Override
        public void run() {
            currentRunnable.run();
            while (true){
                try {
                    System.out.println(new Date().getTime() + " start");
                    Runnable test = blockingQueue.poll(timeout, time);
                    if (test == null ){
                        System.out.println(new Date().getTime() + " end");
                        break;
                    }
                    test.run();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }
    }
}
